package IA;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ArrayList;

/**
 *
 * @author Jeremy
 */
public class SimilarItemCookStrategy implements CookStrategy {
    /*
     * GOAL: Return items that are most similar to the ones in the cooking queue
     * (cookingItems) based on name, from the item queue If it runs out of items
     * on the grill, it reverts to chronological STRATEGY: 1. group items on the
     * grill, and get number of each 2. for the most frequent, find the
     * instances of it in the queue 3. case 1: more needed than in queue-->add
     * all to return list remove most frequent from queue, repeat step 2 4. case
     * 2: more in queue than needed-->add as many as needed to fill return list
     * and exit early 5. If there are no items on the grill, or none matching
     * queue items, default to chronlogical
     */

    @Override
    public ArrayList<CookItem> getNextOrders(ArrayList<CookItem> cookingItems, ArrayList<CookItem> queueItems, int NumNeeded) {
        ArrayList<CookItem> ItemsToReturn = new ArrayList<CookItem>();
        //make a copy of the items in the queue
        ArrayList<CookItem> queue = (ArrayList<CookItem>) queueItems.clone();
        int NumFetched = 0;
        //create a map for the items on the grill: each unique name to the number currently cooking
        HashMap<String, Integer> NameInstances = new HashMap<String, Integer>();
        //populate the frequency map
        for (CookItem c : cookingItems) {
            Integer NumInstances = NameInstances.get(c.getName());
            NameInstances.put(c.getName(), (NumInstances == null) ? 1 : ++NumInstances);
        }
        while (NumFetched < NumNeeded && !queue.isEmpty()) {
            //find the most frequent item 'on the grill'
            String MostFrequentCookingItem = MostFrequent(NameInstances);
            //there exists a grill item we have yet to examine
            if (MostFrequentCookingItem != null) {
                NameInstances.remove(MostFrequentCookingItem);
                ArrayList<CookItem> ItemsFromQueue = RemoveAllMatching(queue, MostFrequentCookingItem);
                if (!ItemsFromQueue.isEmpty()) {
                    Iterator<CookItem> itr = ItemsFromQueue.iterator();
                    //add them to the return list (or as many as needed)
                    while (NumFetched < NumNeeded && itr.hasNext()) {
                        ItemsToReturn.add(itr.next());
                        NumFetched++;
                    }
                }
            } //if MostFrequentCookingItem null, 
            //         1. No Items on Grill to start with
            //         2. Items on grill, but none match queue items (we have gone through grill items and all have been removed)
            //         3. Some grill items matched queue, but there no more matching and we still have more to add
            else {
                //get item chronologically
                CookItem c = queue.get(0);
                ItemsToReturn.add(c);
                queue.remove(c);
                NumFetched++;
            }
        }
        return ItemsToReturn;
    }

    private String MostFrequent(HashMap<String, Integer> m) {
        if (m.isEmpty()) {
            return null;
        }
        String MostFrequentKey = m.keySet().iterator().next();
        for (Iterator<Map.Entry<String, Integer>> itr = m.entrySet().iterator(); itr.hasNext();) {
            Map.Entry<String, Integer> e = itr.next();
            if (e.getValue() > m.get(MostFrequentKey)) {
                MostFrequentKey = e.getKey();
            }
        }
        return MostFrequentKey;
    }

    private ArrayList<CookItem> RemoveAllMatching(ArrayList<CookItem> list, String name) {
        //find all items with matching name and remove them
        ArrayList<CookItem> ItemsToReturn = new ArrayList<CookItem>();
        for (Iterator<CookItem> itr = list.iterator(); itr.hasNext();) {
            CookItem c = itr.next();
            if (c.getName().equals(name)) {
                ItemsToReturn.add(c);
                itr.remove();
            }
        }
        return ItemsToReturn;
    }
}
